# data_dir = join(expanduser("~"), "Desktop/workshopdata")
data_dir = "../../shared/2023-VITALS-Workshop-AGU/data/" #!TODO
data_dir'/Users/cweeks/Desktop/workshopdata'
Authors: Gregory Halverson Claire Villanueva-Weeks Jet Propulsion Laboratory, California Institute of Technology
This research was carried out at the Jet Propulsion Laboratory, California Institute of Technology, and was sponsored by ECOSTRESS and the National Aeronautics and Space Administration (80NM0018D0004).
© 2023. All rights reserved.
Santa Barbara County is a well known for its viticulture. Positioned near the ocean, the unique topography of Santa Barbara allows for unique microclimates that yield diverse crops and wines. In this notebook, we aim to visualize and analyze Vineyard health using Earth observation data from two different satellite products: the EMIT L2A Reflectance product stored in NETCDF4 format and an ECOSTRESS L2 Land Surface Temperature product stored in GEOTIFF format. Our goal is to visualize Normalized Difference Vegetation Index (NDVI), Estimated Water Thickness (EWT), Evapotranspiration (ET), and Surface Temperature (ST) interactively in holoviews maps and generate linear regression plots of point source data.
01_Finding_Concurrent_Data.ipynb - Finding and downloading concurrent EMIT and ECOSTRESS data with earthaccess
03_EMIT_CWC_from_Reflectance.ipynb - Calculating EWT of ROI
03_EMIT_Inreractive_Points.ipynb - Generating a map with clickable points
5.1 Set up 5.2 Locating Data Sources and Loading Data 5.3 Color Hex-Codes for Raster Plots 5.4 Subseting the data over our ROI 5.5 Interactive Maps 5.6 Scatter Plots
These are some built-in Python functions we need for this notebook, including functions for handling filenames and dates.
We’re using the rioxarray package for loading raster data from a GeoTIFF file, and we’re importing it as rxr. We’re using the numpy library to handle arrays, and we’re importing it as np. We’re using the rasterio package to subset the data.
We’re using the geopandas library to load vector data from GeoJSON files, and we’re importing it as gpd. We’re using the shapely library to handle vector data and the pyproj library to handle projections.
Import the emit_tools module and call use from emit_tools import emit_xarray help(emit_xarray) the help function to see how it can be used.
Note: This function currently works with L1B Radiance and L2A Reflectance Data.
import os
from os.path import join, expanduser, splitext, basename
import numpy as np
import pandas as pd
import geopandas as gpd
import rioxarray as rxr
import holoviews as hv
import hvplot.xarray
import hvplot.pandas
import geoviews as gv
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import rasterio as rio
from holoviews.streams import SingleTap
from scipy.stats import linregressImporting Custom EMIT Tools to handle the EMIT reflectance data
# sys.path,append thing might work in 2i2c instead
from modules.emit_tools import emit_xarray, ortho_xrWe can define these constants to prescribe the dimensions of our figures. Feel free to adjust these to fit your display. We’re setting the alpha to make the raster semi-transparent on top of the basemap.
FIG_WIDTH_PX = 1080
FIG_HEIGHT_PX = 720
FIG_WIDTH_IN = 16
FIG_HEIGHT_IN = 9
FIG_ALPHA = 0.7
BASEMAP = "EsriImagery"
SEABORN_STYLE = "whitegrid"
FILL_COLOR = "none"
LINE_COLOR = "red"
LINE_WIDTH = 3
WEBMAP_PROJECTION = "EPSG:3857"
sns.set_style(SEABORN_STYLE)Here we are defining location of EMIT and ECOSTRESS raster files.
# data_dir = join(expanduser("~"), "Desktop/workshopdata")
data_dir = "../../shared/2023-VITALS-Workshop-AGU/data/" #!TODO
data_dir'/Users/cweeks/Desktop/workshopdata'
Here we are loading in our vector data source. We can image the delineated agricultural field boundaries and take a look at the fields.
ag_file = join(data_dir,"SB_ROI_ag.geojson")
# cut out the agroi section
ag_latlon = gpd.read_file(ag_file)
ag_fig = ag_latlon.to_crs(WEBMAP_PROJECTION).hvplot.polygons(
tiles=BASEMAP,
line_color = LINE_COLOR,
line_width = LINE_WIDTH,
fill_color = FILL_COLOR
)
ag_figUnable to display output for mime type(s):
ag_latlon| OBJECTID | permittee | site_name | size | size_units | crop_list | calc_acres | mtrs | geometry | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 3654110 | CENT ANNI-COASTAL VINEYARD CARE | CENT ANNI | 8.0 | ACRES | VERTEBRATE CTRL, GRAPE, WINE, UNCULTIVATED AG | 1.463097 | S07N34W11 | MULTIPOLYGON (((-8064.151 -373076.101, -8058.8... |
| 1 | 3671186 | CENT ANNI-COASTAL VINEYARD CARE | CENT ANNI | 8.0 | ACRES | VERTEBRATE CTRL, GRAPE, WINE, UNCULTIVATED AG | 1.232124 | S07N34W11 | MULTIPOLYGON (((-8220.677 -373296.021, -8205.1... |
| 2 | 3671187 | CENT ANNI-COASTAL VINEYARD CARE | CENT ANNI | 8.0 | ACRES | VERTEBRATE CTRL, GRAPE, WINE, UNCULTIVATED AG | 2.782784 | S07N34W11 | MULTIPOLYGON (((-8185.460 -372957.510, -8146.0... |
| 3 | 4829810 | CHUMASH VINEYARDS LLC- COASTAL VINEYARD | CAMP 4 - | 280.0 | ACRES | VERTEBRATE CTRL, GRAPE, WINE, UNCULTIVATED AG | 277.792034 | S06N30W05 | MULTIPOLYGON (((-5734.564 -375663.536, -5340.6... |
| 4 | 3681606 | GREAT OAKS RANCH-FINKLE | GREAT OAKS RANCH VINEYARD - ALL PLOTS | 20.0 | ACRES | VERTEBRATE CTRL, GRAPE, WINE, UNCULTIVATED AG | 15.713672 | S07N30W30 | MULTIPOLYGON (((-8104.976 -374002.479, -8098.9... |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 463 | 8928511 | BROTHERS BEST PRODUCE | ARBELAITZ RANCH | 12.0 | ACRES | OAT, Rotational Crops | 11.131229 | S07N31W36 | MULTIPOLYGON (((-8961.836 -375463.076, -8960.0... |
| 464 | 8928512 | BROTHERS BEST PRODUCE | SITE 06: MORO RANCH TRI-CLOR EC | 15.0 | ACRES | SQUASH | 14.690810 | S07N30W32 | MULTIPOLYGON (((-4728.422 -374455.107, -4732.8... |
| 465 | 8928514 | BROTHERS BEST PRODUCE | SHEPPARD RANCH | 108.0 | ACRES | OAT, Rotational Crops | 110.279936 | S06N30W05 | MULTIPOLYGON (((-6938.727 -376457.113, -5628.6... |
| 466 | 8945655 | CAMARILLO FARMING | SITE 01 BASELINE AVE RANCH | 8.0 | ACRES | PEPPER FRUITNG, TOMATILLO, CABBAGE | 7.910668 | S07N31W36 | MULTIPOLYGON (((-8567.652 -375377.567, -8567.0... |
| 467 | 8947580 | TANNER VINEYARD | TANNER RANCH | 1.0 | ACRES | GRAPE, WINE | 1.006459 | S06N31W01 | MULTIPOLYGON (((-8856.269 -376329.948, -8907.5... |
468 rows × 9 columns
To open up the EMIT .nc file we will use the netCDF4, xarray and emit_tools libraries.
EMIT_fp = join(data_dir, "EMIT_L2A_RFL_001_20230401T203803_2309114_003.nc") #!TODO change to 2i2c path later
EMIT_fp'/Users/cweeks/Desktop/workshopdata/EMIT_L2A_RFL_001_20230401T203803_2309114_003.nc'
refl_ds = emit_xarray(EMIT_fp, ortho=True)
refl_ds<xarray.Dataset>
Dimensions: (latitude: 1895, longitude: 2368, wavelengths: 285)
Coordinates:
* wavelengths (wavelengths) float32 381.0 388.4 ... 2.486e+03 2.493e+03
fwhm (wavelengths) float32 ...
good_wavelengths (wavelengths) float32 ...
* latitude (latitude) float64 35.31 35.3 35.3 ... 34.28 34.28 34.28
* longitude (longitude) float64 -120.3 -120.3 -120.3 ... -119.1 -119.1
elev (latitude, longitude) float32 nan nan nan ... nan nan nan
spatial_ref int64 0
Data variables:
reflectance (latitude, longitude, wavelengths) float32 nan nan ... nan
Attributes: (12/40)
ncei_template_version: NCEI_NetCDF_Swath_Template_v2.0
summary: The Earth Surface Mineral Dust Source ...
keywords: Imaging Spectroscopy, minerals, EMIT, ...
Conventions: CF-1.63
sensor: EMIT (Earth Surface Mineral Dust Sourc...
instrument: EMIT
... ...
spatial_ref: GEOGCS["WGS 84",DATUM["WGS_1984",SPHER...
geotransform: [-1.20348784e+02 5.42232520e-04 -0.00...
day_night_flag: Day
title: EMIT L2A Estimated Surface Reflectance...
granule_id: EMIT_L2A_RFL_001_20230401T203803_23091...
Orthorectified: TrueHere some functions are set up to
Here we have set up convenience functions for interpolating Color Hex-Codes for Raster Plots
def interpolate_hex(hex1, hex2, ratio):
rgb1 = [int(hex1[i:i+2], 16) for i in (1, 3, 5)]
rgb2 = [int(hex2[i:i+2], 16) for i in (1, 3, 5)]
rgb = [int(rgb1[i] + (rgb2[i] - rgb1[i]) * ratio) for i in range(3)]
return '#{:02x}{:02x}{:02x}'.format(*rgb)
def create_gradient(colors, steps):
gradient = []
for i in range(len(colors) - 1):
for j in range(steps):
ratio = j / float(steps)
gradient.append(interpolate_hex(colors[i], colors[i+1], ratio))
gradient.append(colors[-1])
return gradient
def plot_cmap(cmap):
gradient = np.linspace(0, 1, 256) # Gradient from 0 to 1
gradient = np.vstack((gradient, gradient)) # Make 2D image
# Display the colormap
plt.figure(figsize=(6, 2))
plt.imshow(gradient, aspect='auto', cmap=cmap)
plt.axis('off')
plt.show()These are the nearest to 800 nm and 675 nm wavelengths, they can be used to calculate the NDVI using a ratio of the difference between between the wavelengths to the sum of the wavelengths. NDVI is a metric by which we can estimate vegetation greenness.
The hvplot package extends xarray to allow us to plot maps. We’re reprojecting the raster geographic projection EPSG 4326 to overlay on the basemap with a latitude and longitude graticule. We will be using hvplot a few more times to look at the data we are using.
NIR_colors = ["#000000", "#FF0000"]
NIR_gradient = create_gradient(NIR_colors, 100)
NIR_cmap = LinearSegmentedColormap.from_list(name="NIR", colors=NIR_colors)
plot_cmap(NIR_cmap)
NIR = refl_ds.sel(wavelengths=800, method="nearest")
NIR.rio.to_raster("NIR_800.tif")
NIR = rxr.open_rasterio('NIR_800.tif').squeeze("band", drop=True)
NIR_vmin, NIR_vmax = np.nanquantile(np.array(NIR), [0.02, 0.98])
NIR_title = f"{splitext(basename(EMIT_fp))[0]} ~800 nm"
NIR.rio.reproject("EPSG:3857").hvplot.image(
geo=True,
rasterize=True,
cmap=NIR_gradient,
alpha=FIG_ALPHA,
tiles=BASEMAP,
clim=(NIR_vmin, NIR_vmax),
title=NIR_title
)red_colors = ["#000000", "#FF0000"]
red_gradient = create_gradient(red_colors, 100)
red_cmap = LinearSegmentedColormap.from_list(name="red", colors=red_colors)
plot_cmap(red_cmap)
red = refl_ds.sel(wavelengths=675, method="nearest")
red.rio.to_raster("red_675.tif")
red = rxr.open_rasterio('red_675.tif').squeeze("band", drop=True)
red_vmin, red_vmax = np.nanquantile(np.array(red), [0.02, 0.98])
red_title = f"{splitext(basename(EMIT_fp))[0]} ~675 nm"
red.rio.reproject("EPSG:3857").hvplot.image(
geo=True,
rasterize=True,
cmap=red_gradient,
alpha=FIG_ALPHA,
tiles=BASEMAP,
clim=(red_vmin, red_vmax),
title=red_title
)NDVI_colors=[
"#0000ff",
"#000000",
"#745d1a",
"#e1dea2",
"#45ff01",
"#325e32"
]
NDVI_gradient = create_gradient(NDVI_colors, 100)
NDVI_cmap = LinearSegmentedColormap.from_list(name="NDVI", colors=NDVI_colors)
plot_cmap(NDVI_cmap)Task exception was never retrieved
future: <Task finished name='Task-168' coro=<Callback.process_on_change() done, defined at /opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py:355> exception=UnsetValueError("figure(id='p10639', ...).inner_height doesn't have a value set")>
Traceback (most recent call last):
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 374, in process_on_change
msg[attr] = self.resolve_attr_spec(path, cb_obj)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 281, in resolve_attr_spec
resolved = getattr(resolved, p, None)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/bokeh/core/property/descriptors.py", line 283, in __get__
raise UnsetValueError(f"{obj}.{self.name} doesn't have a value set")
bokeh.core.property.descriptors.UnsetValueError: figure(id='p10639', ...).inner_height doesn't have a value set
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 379, in process_on_change
msg[attr] = self.resolve_attr_spec(path, cb_obj)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 281, in resolve_attr_spec
resolved = getattr(resolved, p, None)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/bokeh/core/property/descriptors.py", line 283, in __get__
raise UnsetValueError(f"{obj}.{self.name} doesn't have a value set")
bokeh.core.property.descriptors.UnsetValueError: figure(id='p10639', ...).inner_height doesn't have a value set
Task exception was never retrieved
future: <Task finished name='Task-173' coro=<Callback.process_on_change() done, defined at /opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py:355> exception=UnsetValueError("figure(id='p10735', ...).inner_height doesn't have a value set")>
Traceback (most recent call last):
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 374, in process_on_change
msg[attr] = self.resolve_attr_spec(path, cb_obj)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 281, in resolve_attr_spec
resolved = getattr(resolved, p, None)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/bokeh/core/property/descriptors.py", line 283, in __get__
raise UnsetValueError(f"{obj}.{self.name} doesn't have a value set")
bokeh.core.property.descriptors.UnsetValueError: figure(id='p10735', ...).inner_height doesn't have a value set
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 379, in process_on_change
msg[attr] = self.resolve_attr_spec(path, cb_obj)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 281, in resolve_attr_spec
resolved = getattr(resolved, p, None)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/bokeh/core/property/descriptors.py", line 283, in __get__
raise UnsetValueError(f"{obj}.{self.name} doesn't have a value set")
bokeh.core.property.descriptors.UnsetValueError: figure(id='p10735', ...).inner_height doesn't have a value set

NDVI = (NIR - red)/(NIR + red)
NDVI.rio.to_raster("NDVI.tif")
NDVI = rxr.open_rasterio("NDVI.tif").squeeze("band", drop=True)
NDVI_vmin, NDVI_vmax = np.nanquantile(np.array(NDVI), [0.02, 0.98])
NDVI_title = "Normalized Difference Vegetation Index"
NDVI_scene_map = NDVI.rio.reproject("EPSG:3857").hvplot.image(
geo=True,
rasterize=True,
cmap=NDVI_gradient,
alpha=FIG_ALPHA,
tiles=BASEMAP,
clim=(NDVI_vmin, NDVI_vmax),
title=NDVI_title
)
NDVI_scene_mapWe can now open up the EWT data that you calculated earlier with the LP DAAC EWT !TODO. The dataset is now in .tif format which means we can just open this one up
EWT_filename = join(data_dir,'EMIT_L2A_RFL_001_20230401T203751_2309114_002_roi_bbox_cwc_merged.tif') #!TODO change to 2i2c path later
EWT_filename'/Users/cweeks/Desktop/workshopdata/EMIT_L2A_RFL_001_20230401T203751_2309114_002_roi_bbox_cwc_merged.tif'
EWT_colors = ["#FFFFFF", "#0000FF"]
EWT_gradient = create_gradient(EWT_colors, 100)
EWT_cmap = LinearSegmentedColormap.from_list(name="EWT", colors=EWT_colors)
plot_cmap(EWT_cmap)
EWT = rxr.open_rasterio(EWT_filename).squeeze("band", drop=True)
EWT_vmin, EWT_vmax = np.nanquantile(np.array(EWT), [0.02, 0.98])
EWT_title = "Estimated Water Thickness "
EWT.rio.reproject("EPSG:3857",nodata=np.nan).hvplot.image(
geo=True,
rasterize=True,
cmap=EWT_gradient,
alpha=FIG_ALPHA,
tiles=BASEMAP,
clim=(EWT_vmin, EWT_vmax),
title=EWT_title
)ST_filename = join(data_dir, "ECOv002_L2T_LSTE_26860_001_10SGD_20230401T203733_0710_01_LST.tif") #!TODO change to 2i2c path later
ST_filenameTask exception was never retrieved
future: <Task finished name='Task-186' coro=<Callback.process_on_change() done, defined at /opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py:355> exception=UnsetValueError("figure(id='p10831', ...).inner_height doesn't have a value set")>
Traceback (most recent call last):
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 374, in process_on_change
msg[attr] = self.resolve_attr_spec(path, cb_obj)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 281, in resolve_attr_spec
resolved = getattr(resolved, p, None)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/bokeh/core/property/descriptors.py", line 283, in __get__
raise UnsetValueError(f"{obj}.{self.name} doesn't have a value set")
bokeh.core.property.descriptors.UnsetValueError: figure(id='p10831', ...).inner_height doesn't have a value set
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 379, in process_on_change
msg[attr] = self.resolve_attr_spec(path, cb_obj)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/holoviews/plotting/bokeh/callbacks.py", line 281, in resolve_attr_spec
resolved = getattr(resolved, p, None)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Caskroom/mambaforge/base/envs/AGUworkshop/lib/python3.11/site-packages/bokeh/core/property/descriptors.py", line 283, in __get__
raise UnsetValueError(f"{obj}.{self.name} doesn't have a value set")
bokeh.core.property.descriptors.UnsetValueError: figure(id='p10831', ...).inner_height doesn't have a value set
'/Users/cweeks/Desktop/workshopdata/ECOv002_L2T_LSTE_26860_001_10SGD_20230401T203733_0710_01_LST.tif'
The temperatures in the L2T_LSTE product are given in Kelvin. To convert them to Celsius, we subtract 273.15.
ST_K = rxr.open_rasterio(ST_filename).squeeze('band', drop=True)
ST_C = ST_K - 273.15
ST_C.rio.to_raster("ST.tif")
ST_vmin, ST_vmax = np.nanquantile(np.array(ST_C), [0.02, 0.98])
ST_title = "ECOSTRESS Surface Temperature (Celsius)"
ST_C.rio.reproject("EPSG:3857",nodata=np.nan).hvplot.image(
geo=True,
rasterize=True,
cmap="jet",
alpha=FIG_ALPHA,
tiles=BASEMAP,
clim=(ST_vmin, ST_vmax),
title=ST_title
)Color ramps, are used to map valued over a range of colors based on the data and goals of visualization. We’ve traditionally used the “jet” rainbow color-scheme to represent temperature, but this color-scheme is not accessible for all vision types.
Red-green colorblindness or Deuteranomoly affects approxiately 10% of people, so we are working on making a color ramp with that in mind. You can use hex codes to program in your own colors!
ST_colors = [
"#054fb9",
"#0073e6",
"#8babf1",
"#cccccc",
"#e1ad01",
"#f57600",
"#c44601"
]
ST_gradient = create_gradient(ST_colors, 100)
ST_cmap = LinearSegmentedColormap.from_list(name="ST", colors=ST_colors)
plot_cmap(ST_cmap)
ST_vmin, ST_vmax = np.nanquantile(np.array(ST_C), [0.02, 0.98])
ST_title = "ECOSTRESS Surface Temperature (Celsius)"
ST_C.rio.reproject("EPSG:3857").hvplot.image(
geo=True,
rasterize=True,
cmap=ST_gradient,
alpha=FIG_ALPHA,
tiles=BASEMAP,
clim=(ST_vmin, ST_vmax),
title=ST_title
)ET_filename = join(data_dir, "ECOv002_L3T_JET_26860_001_10SGD_20230401T203732_0700_01_ETdaily.tif")
ET_filename'/Users/cweeks/Desktop/workshopdata/ECOv002_L3T_JET_26860_001_10SGD_20230401T203732_0700_01_ETdaily.tif'
We have an established color-map for representing ECOSTRESS evapotranspiration that we believe to be inclusive.
ET_colors = [
"#f6e8c3",
"#d8b365",
"#99974a",
"#53792d",
"#6bdfd2",
"#1839c5"
]
ET_gradient = create_gradient(ET_colors, 100)
ET_cmap = LinearSegmentedColormap.from_list(name="ET", colors=ET_colors)
plot_cmap(ET_cmap)
The daily evapotranspiration product from ECOSTRESS is given in millimeters per day.
ET = rxr.open_rasterio(ET_filename).squeeze('band', drop=True)
ET_vmin, ET_vmax = np.nanquantile(np.array(ET), [0.02, 0.98])
ET_title = "ECOSTRESS Evapotranspiration (mm / day)"
ET.rio.reproject("EPSG:3857").hvplot.image(
geo=True,
raETerize=True,
cmap=ET_gradient,
alpha=FIG_ALPHA,
tiles=BASEMAP,
clim=(ET_vmin, ET_vmax),
title=ET_title
)WARNING:param.main: raETerize option not found for image plot with bokeh; similar options include: ['rasterize']
Unable to display output for mime type(s):